package com.xneure.code.log;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import com.xneure.code.intf.LogOptimize;
import com.xneure.utils.JsonUtil;
import com.xneure.utils.StackUtil;
import com.xneure.utils.bean.Caller;

@Component("log")
public class PrintLog implements ILog,InitializingBean{
	private String[] clss = {System.out.getClass().getSimpleName(),"Category","Jdk14Logger","Throwable","FilterOutputStream","SysPrintHandle","DirectJDKLog","PrintLog"};
	private List<LogWatcher> filters;
	private String clsName;
	private Caller[] callers;
	private int isSysOut = -1;
	private boolean sysHandle;

	public PrintLog(Class<?> cls){
		this(cls.getName());
	}

	public PrintLog(String clsName){
		this.clsName = clsName;
	}

	public PrintLog(){
		this(StackUtil.getFirstCaller().getClassName());
	}

	public synchronized void addWatcher(LogWatcher filter){
		if(null == filters){
			filters = new ArrayList<LogWatcher>();
		}
		if(filters.contains(filter) == false){
			filters.add(filter);
		}
	}

	public void debug(Object log){
		print(Level.DEBUG,log);
	}

	public void error(Object log){
		print(Level.ERROR,log);
	}

	public void info(Object log){
		print(Level.INFO,log);
	}

	public void warn(Object log){
		print(Level.WARN,log);
	}

	public void print(Level l,Object log){
		if(null != filters){
			if(null != log){
				if(System.lineSeparator().equals(log)){
					return;
				}
			}
			int ordinal = l.ordinal() - 1;
			callers = StackUtil.getCaller(clss);
			if(isSysHandle()){
				isSysOut = isSysOut(callers[0]);
			}else{
				isSysOut = 0;
			}
			for(LogWatcher logWatcher:filters){
				if(null != logWatcher.level && logWatcher.level.ordinal() > ordinal){
					String str = "null";
					if(null == log){
						log = str;
					}
					if(log.getClass().isPrimitive() || log instanceof String || log instanceof Date){
						str = log.toString();
					}else{
						str = JsonUtil.toJson(log);
					}
					if(str.endsWith("\r\n") == false){
						str = str.concat("\r\n");
					}
					logWatcher.handle(this,l,str);
				}
			}
		}
	}

	@Override
	public void close() throws IOException{
		if(null != filters){
			filters.clear();
		}
		filters = null;
	}

	@Override
	public Caller getCaller(){
		return callers[isSysOut];
	}

	private final int isSysOut(Caller stack){
		if(stack.getClassName().equals("java.io.PrintStream")){
			return "println".contains(stack.getMethodName()) ? 1 : 0;
		}
		return 0;
	}

	@Override
	public String useClass(){
		return clsName;
	}

	@Override
	public boolean isSysPrint(){
		return isSysOut == 1;
	}

	@Override
	public boolean isSysHandle(){
		return sysHandle;
	}

	@Override
	public void setSysHandle(boolean sysHandle){
		this.sysHandle = sysHandle;
	}

	@Override
	public void afterPropertiesSet() throws Exception{
		LogManage.registerLog(this);
	}

	@Override
	public void log(Level level,LogOptimize fun){
		print(level,fun.value());
	}
}
